package com.gopay.bis.manager.bank.ebank;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;

import com.gopay.bis.common.util.BankLogUtils;
import com.gopay.bis.common.util.TransUtils;
import com.gopay.common.Result;
import com.gopay.common.constants.bank.BankConstants;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.BaseMessage;
import com.gopay.common.domain.bank.icbc.ebank.pay.IcbcB2bMessage;
import com.gopay.common.domain.bank.icbc.ebank.query.req.CmsQueryB2BReq;
import com.gopay.common.domain.bank.icbc.ebank.query.req.EbQueryB2BReq;
import com.gopay.common.domain.bank.icbc.ebank.query.req.InQueryB2BReq;
import com.gopay.common.domain.bank.icbc.ebank.query.req.PubQueryB2BReq;
import com.gopay.common.domain.bank.icbc.ebank.query.res.CmsQueryB2BRes;
import com.gopay.common.exception.GopayException;
import com.gopay.common.util.DateUtils;
import com.gopay.remote.bank.BankManagerRemoteService;
import com.gopay.remote.bank.businesses.BankService;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

/**
 * 工行支付网关B2B对象封装
 * 
 * IcbcB2BManager.java
 * @author WangHongFei
 */
public class IcbcB2bManager implements BankManagerRemoteService {
    
    private static final String XMLHEADER_QUERY = "<?xml version=\"1.0\" encoding=\"GB2312\" ?>\n";
    
    @Resource(name = "icbcB2bBankServiceClient")
    private BankService icbcB2bBankServiceClient;
    
    @Resource(name = "icbcConfig")
    private Map<String, String> icbcConfig;
    
    /**
     * 工行B2B签名
     * 
     * @param BaseMessage
     * @return Object
     * @throws GopayException
     */
    public Object sign(BaseMessage message) throws GopayException {     
        IcbcB2bMessage messageB2B = (IcbcB2bMessage) message;
        messageB2B.setMerchantUrl(messageB2B.getPayRuturnUrl());
        messageB2B.setApiName(icbcConfig.get("ICBC.B2B.APINAME"));
        messageB2B.setApiVersion(icbcConfig.get("ICBC.B2B.APIVERSION"));
        messageB2B.setShopCode(messageB2B.getMerID());
        messageB2B.setJoinFlag(icbcConfig.get("ICBC.B2B.JOINFLAG"));
        messageB2B.setSendType(icbcConfig.get("ICBC.B2B.SENDTYPE"));
        messageB2B.setShopAccnum(icbcConfig.get("ICBC.B2B.SHOP.ACC.NUM"));
        messageB2B.setPayeeacct(icbcConfig.get("ICBC.B2B.SHOP.ACC.NUM"));
        messageB2B.setAccountCur(icbcConfig.get("ICBC.CURCODE.RMB"));
        messageB2B.setBankUrl(messageB2B.getPayUrl());
        messageB2B.setCarriageAmt(TransUtils.amountConvert2Fen(message.getAmount().toString()));
        messageB2B.setContractAmt(TransUtils.amountConvert2Fen(message.getAmount().toString()));
        if (StringUtils.isNotBlank(messageB2B.getPaymentAccInfo())) {
            messageB2B.setShopRemark(message.getPaymentAccInfo());
            messageB2B.setShopRem(message.getPaymentAccInfo());
        }
        
        String plainMessage = buildPlain(messageB2B);
        messageB2B.setPlainMessage(plainMessage);
        BankLogUtils.printB2BManagerSignSendLog(messageB2B);
        messageB2B = (IcbcB2bMessage) icbcB2bBankServiceClient.sign(messageB2B);
        BankLogUtils.printB2BManagerSignReturnLog(messageB2B);
        return messageB2B;
    }

    /**
     * 工行B2B验签
     * 
     * @param BaseMessage
     * @return Object
     * @throws GopayException
     */
    public Object verify(BaseMessage message) throws GopayException {
        IcbcB2bMessage messageB2B = (IcbcB2bMessage) message;
        StringBuffer sb = new StringBuffer("");
        sb.append("APIName=" + messageB2B.getApiName());
        sb.append("&APIVersion=" + messageB2B.getApiVersion());
        sb.append("&Shop_code=" + messageB2B.getShopCode());
        sb.append("&MerchantURL=" + messageB2B.getMerchantUrl());
        sb.append("&Serial_no=" + messageB2B.getSerialNo());
        sb.append("&PayStatusZHCN=" + messageB2B.getPayStatusZHCN());
        sb.append("&TranErrorCode=" + messageB2B.getTranErrorCode());
        sb.append("&TranErrorMsg=" + messageB2B.getTranErrorMsg());
        sb.append("&ContractNo=" + messageB2B.getContractNo());
        sb.append("&ContractAmt=" + messageB2B.getContractAmt());
        sb.append("&Account_cur=" + messageB2B.getAccountCur());
        sb.append("&JoinFlag=" + messageB2B.getJoinFlag());
        sb.append("&ShopJoinFlag=" + messageB2B.getShopJoinFlag());
        sb.append("&CustJoinFlag=" + messageB2B.getCustJoinFlag());
        sb.append("&CustJoinNumber=" + messageB2B.getCustJoinNumber());
        sb.append("&SendType=" + messageB2B.getSendType());
        sb.append("&TranTime=" + messageB2B.getTranTime());
        sb.append("&NotifyTime=" + messageB2B.getNotifyTime());
        sb.append("&Shop_acc_num=" + messageB2B.getShopAccnum());
        sb.append("&PayeeAcct=" + messageB2B.getPayeeacct());
        sb.append("&PayeeName=" + messageB2B.getPayeeName());
        messageB2B.setPlainMessage(sb.toString());
        BankLogUtils.printB2BManagerVerifySendLog(messageB2B);
        boolean flag = (Boolean) icbcB2bBankServiceClient.verify(messageB2B);
        BankLogUtils.printB2BManagerVerifyReturnLog(messageB2B, flag);
        return flag;
    }

    /**
     * 工行B2B查询
     * 
     * @param Object
     * @return Object
     * @throws GopayException
     */
    public Object query(Object message) throws GopayException {
        IcbcB2bMessage messageB2B = (IcbcB2bMessage) message;
        CmsQueryB2BReq cms = buildCms(messageB2B);
        Map<String, String> param = queryParam(cms);
        BankLogUtils.printB2BManagerQuerySendLog(messageB2B, param);
        CmsQueryB2BRes res = (CmsQueryB2BRes) icbcB2bBankServiceClient.query(param);
        res.setOutStlmCd(BankConstants.BANK_LOGO_ICBC); // 为了区分日志输出
        BankLogUtils.printB2BManagerQueryReturnLog(res);
        return res;
    }
    
    /**
     * 构建B2B明文串
     * 
     * @param IcbcB2bMessage
     * @return String
     */
    private String buildPlain(IcbcB2bMessage message) {
        StringBuffer sb = new StringBuffer(512);
        sb.append("APIName=").append(message.getApiName());
        sb.append("&APIVersion=").append(message.getApiVersion());
        sb.append("&Shop_code=").append(message.getShopCode());
        sb.append("&MerchantURL=").append(message.getMerchantUrl());
        sb.append("&ContractNo=").append(message.getOrderId());
        sb.append("&ContractAmt=").append(message.getContractAmt());
        sb.append("&Account_cur=").append(message.getAccountCur());
        sb.append("&JoinFlag=").append(message.getJoinFlag());
        sb.append("&SendType=").append(message.getSendType());
        sb.append("&TranTime=").append(message.getOrderDate());
        sb.append("&Shop_acc_num=").append(message.getShopAccnum());
        sb.append("&PayeeAcct=").append(message.getPayeeacct());
        return sb.toString();
    }

    private Map<String, String> queryParam(CmsQueryB2BReq req) {
        XStream xs = new XStream(new DomDriver());
        xs.autodetectAnnotations(true);
        // 生成请求报文
        String reqData = xs.toXML(req);
        StringBuffer sb = new StringBuffer(XMLHEADER_QUERY);
        sb.append(reqData);
        EbQueryB2BReq eb = req.getEb();
        PubQueryB2BReq pub = eb.getPub();
        Map<String, String> param = new HashMap<String, String>();
        param.put("userID", pub.getId());
        param.put("PackageID", pub.getFseqNo());
        param.put("SendTime", DateUtils.getCurrDate("yyyyMMddHHmmssSSS"));
        param.put("Version", icbcConfig.get("ICBC.QUERY.VERSION"));
        param.put("TransCode", pub.getTransCode());
        param.put("BankCode", pub.getBankCode());
        param.put("GroupCIS", pub.getCis());
        param.put("ID", pub.getId());
        param.put("PackageID", pub.getFseqNo());
        param.put("Cert", "");
        param.put("reqData", sb.toString());
        // 设置B2B交易
        param.put("tradeType", BankConstants.TRADE_B2B + "");
        param.put("queryUrl", req.getQueryUrl());
        return param;
    }

    private CmsQueryB2BReq buildCms(IcbcB2bMessage message) {
        CmsQueryB2BReq cms = new CmsQueryB2BReq();
        EbQueryB2BReq eb = new EbQueryB2BReq();
        PubQueryB2BReq pub = new PubQueryB2BReq();
        InQueryB2BReq in = new InQueryB2BReq();
        // 交易代码
        pub.setTransCode(icbcConfig.get("ICBC.B2B.QUERY.TRANDCODE"));
        // 集团CIS
        pub.setCis(icbcConfig.get("ICBC.QUERY.CIS"));
        // 归属银行编号
        pub.setBankCode(icbcConfig.get("ICBC.QUERY.BANKCODE"));
        // 证书ID
        pub.setId(message.getMerID2nd());
        // 交易日期
        pub.setTranDate(DateUtils.getCurrDate("yyyyMMdd"));
        // 交易时间(微秒补零)
        pub.setTranTime(DateUtils.getCurrDate("HHmmssSS") + "000");
        // 指令包序列号
        pub.setFseqNo(TransUtils.getPackageID());
        // 商城类型
        in.setShopType(icbcConfig.get("ICBC.B2B.QUERY.SHOPTYPE"));
        // 商城代码
        in.setShopCode(icbcConfig.get("ICBC.B2B.QUERY.SHOPCODE"));
        // 商城账号
        in.setShopAcct(icbcConfig.get("ICBC.B2B.QUERY.SHOPACCT"));
        // 待查订单号
        in.setQryOrderNum(message.getOrderId());
        // 待查交易序列号
        in.setQrySerialNo(" ");
        // 起始日期
        in.setBeginDate(DateUtils.getCurrDate("yyyyMMdd"));
        // 截止日期
        in.setEndDate(DateUtils.getCurrDate("yyyyMMdd"));
        // 开始时间
        in.setBeginTime("000000");
        // 终止时间
        in.setEndTime("235959");
        // 查询交易状态类型
        in.setResultType(" ");
        // 查询下页标识
        in.setNextTag(" ");
        // 请求备用字段1
        in.setReqRes1(" ");
        // 请求备用字段2
        in.setReqRes2(" ");
        eb.setPub(pub);
        eb.setIn(in);
        cms.setEb(eb);
        cms.setQueryUrl(message.getQueryUrl());
        return cms;
    }

    @Override
    public Object dayend(BaseMessage base) throws GopayException, Exception {
        // TODO Auto-generated method stub
        return null;
    }

	@Override
	public Object refund(BaseMessage base) throws GopayException {
		// TODO Auto-generated method stub
		return null;
	}
}
